package uplb.ics.cs190.e2d.core;

import java.io.InputStream;

import uplb.ics.cs190.e2d.display.Display;
import uplb.ics.cs190.e2d.display.Graphics;
import uplb.ics.cs190.e2d.graphics.Image;
import uplb.ics.cs190.e2d.io.File;
import uplb.ics.cs190.e2d.io.FileIO;
import uplb.ics.cs190.e2d.lang.GSystem;
import uplb.ics.cs190.e2d.lang.GameException;
import uplb.ics.cs190.e2d.time.SystemTimer;

public final class Engine {

	protected static Engine singleton;
	
	protected Game game;
	
	public Display display;
	public SystemTimer timer;
	public FileIO fileIO;
	
	public static Engine getInstance() {
		return singleton = new Engine();
	}

	private boolean isRunning;
	private boolean isPaused;

	protected Engine() {
		this.isRunning = false;
		this.isPaused = false;
	}

	public void mountGame(Game game) throws GameException {
		this.game = game;
		this.game.setEngine(this);
	}

	public void start() {
		init();
		processGame();
	}

	private void processGame() {
		isRunning = true;
		
		this.timer.start();
		this.timer.refresh();
		
		long elapsedTime = 0;
		
		while(isRunning) {
			if(!isPaused) {
				this.game.update(elapsedTime);
			}
			
			do {
				if(!isRunning) {
					break;
				}
				Graphics g = display.getBackBuffer();
				this.game.render(g);
			} while(!this.display.flip());
			
			elapsedTime = this.timer.sleep();
			if(elapsedTime > 100) {
				elapsedTime = 100;
			}
		}
		
		this.cleanup();
	}

	private void init() {
		GSystem.collect();
		game.loadResources();
	}

	public boolean isRunning() {
		return isRunning;
	}

	public void pause() {
		isPaused = true;
	}
	
	public void resume() {
		isPaused = false;
	}

	public boolean isPaused() {
		return isPaused;
	}

	public void stop() {
		isRunning = false;
	}

	public void cleanup() {
		game.destroy();
	}
	
	/* FILE IO */
	public Image getImage(String path) {
		return fileIO.getImage(path);
	}
	
	public File getFile(String path) {
		return fileIO.getFile(path);
	}
	
	public InputStream getInputStream(String path) {
		return fileIO.getInputStream(path);
	}
}
